package com.example.springstudy.base.aspect;

import com.example.springstudy.base.annotation.DataScope;
import com.example.springstudy.base.enume.DataScopeEnum;
import com.example.springstudy.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Aspect
@Component
@Slf4j
@Order(9)
public class DataScopeAspect {

    @Pointcut("@annotation(com.example.springstudy.base.annotation.DataScope)")
    public void dataScopePointCut(){

    }

    @Around("dataScopePointCut()")
    public Object dataScopeBefore(ProceedingJoinPoint joinPoint) throws Throwable {

        Object[] args = joinPoint.getArgs();
        MethodSignature method = (MethodSignature) joinPoint.getSignature();
        log.info("dataScopePointCut:{}", method.getMethod().getName());
        DataScope dataScope = method.getMethod().getAnnotation(DataScope.class);
        if(SecurityUtils.getUser().isEmpty() || SecurityUtils.isRoot()){
            return joinPoint.proceed(args);
        }
        log.info("getUser:{}", SecurityUtils.getUser());
        Long userId = SecurityUtils.getUserId();
        int deptId = SecurityUtils.getDeptId();
        int dataScopeType = SecurityUtils.getDataScope();
        String deptAlias = dataScope.deptAlias();
        String userAlias = dataScope.userAlias();
        String employeeAlias = dataScope.employeeAlias();
        String shopAlias = dataScope.shopAlias();
        StringBuilder sqlString = new StringBuilder();
        if(DataScopeEnum.OWN.getType()==dataScopeType) {
            sqlString.append(" OR ").append(userAlias).append(".id=").append(userId);
        } else if(DataScopeEnum.DEPT_ONLY.getType() == dataScopeType){
            sqlString.append(" OR ").append(deptAlias).append(".id=").append(deptId);
        } else if(DataScopeEnum.DEPT_CHILD.getType() == dataScopeType){
            String selectChildSql = "WITH RECURSIVE cte AS ( SELECT id, name, parent_id FROM dept WHERE id="+deptId+" UNION ALL SELECT d.id, d.name, d.parent_id FROM dept d JOIN cte ON d.parent_id=cte.id)" +
                    "SELECT id FROM cte";
            sqlString.append(" OR ").append(deptAlias).append(".id in (").append(selectChildSql).append(")");
        } else if(DataScopeEnum.SHOP.getType() == dataScopeType){
            sqlString.append(" OR ").append(shopAlias).append(".id=").append(0);
        } else {
            sqlString = new StringBuilder();
        }
        ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
        String[] parameters = pnd.getParameterNames(method.getMethod());
        Map<String, Object> map = new HashMap<>();
        for(int i = 0; i< Objects.requireNonNull(parameters).length; i++){
            map.put(parameters[i], args[i]);
        }
        map.put("extendSql", sqlString.toString());
        log.info("map:{}", map);

//        Object[] newArgs = Arrays.copyOf(args, args.length+1);
//        newArgs[newArgs.length-1] = sqlString.toString();

        log.info("args: {}", args);
        return joinPoint.proceed(args); //修改求情参数
    }

}
